﻿using System.Collections.Generic;
using System.Net.Sockets;

namespace TC.Vacation.Spider.Core.Iocp
{
    /// <summary>
    /// 缓存管理
    /// </summary>
    internal sealed class BufferManager
    {
        private int numBytes;
        private byte[] buffer;
        private Stack<int> freeIndexPool;
        private int currentIndex;
        private int bufferSize;

        /// <summary>
        /// 内存管理(公用缓冲区，防止大量对象创建导致内存分散)
        /// </summary>
        /// <param name="totalBytes">缓存的总大小</param>
        /// <param name="bufferSize">每个缓存的大小</param>
        internal BufferManager(int totalBytes, int bufferSize)
        {
            numBytes = totalBytes;
            currentIndex = 0;
            this.bufferSize = bufferSize;
            freeIndexPool = new Stack<int>();
        }

        /// <summary>
        /// 初始化缓存
        /// </summary>
        internal void InitBuffer()
        {
            buffer = new byte[numBytes];
        }

        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <param name="args">增强型异步缓存上下文类</param>
        /// <returns></returns>
        internal bool SetBuffer(SocketAsyncEventArgs args)
        {
            if (freeIndexPool.Count > 0)
            {
                args.SetBuffer(buffer, freeIndexPool.Pop(), bufferSize);
            }
            else
            {
                if ((numBytes - bufferSize) < currentIndex)
                {
                    return false;
                }
                args.SetBuffer(buffer, currentIndex, bufferSize);
                currentIndex += bufferSize;
            }
            return true;
        }

        /// <summary>
        /// 释放缓存
        /// </summary>
        /// <param name="args">异步套接字</param>
        internal void FreeBuffer(SocketAsyncEventArgs args)
        {
            freeIndexPool.Push(args.Offset);
            args.SetBuffer(null, 0, 0);
        }

        /// <summary>
        /// 获取缓冲池的容量
        /// </summary>
        internal int TotayBytes
        {
            get
            {
                return numBytes;
            }
        }
    }
}
